/* 内存分配器 */
#include "types.h"
#include "defins.h"
#include "params.h"
#include "memory.h"
#include "kfunc.h"
#include "kalloc.h"
#include "util.h"
#include "biscuit.h"
#include "lock.h"
int collectexpgs (void * bg, void *ed);
int kfree (void * pg);

extern char KERNED[]; // provided by linker
struct {
    struct linkpgs *free;
    struct sleeplk lk;
} freemem;

void
kmeminit () { // checked
    void * MEMED = (void*) MAX_MEMSZ; 
    bzero (&freemem, sizeof (freemem));
    //printk ("%p", KERNED);
    // ll_testnum ((int)KERNED);
    //panic ("kmem");
    collectexpgs (KERNED, MEMED);
    //printk ("memed: %p\n",MEMED);
}
int
collectexpgs (void * bg, void *ed) { // checked
    /* 左闭右开 */
    void * pgptr;
    if ((uint32) bg >= (uint32) ed) // 无页面可连接
        goto nopg;
    if (!PGALIGNED(bg) || !PGALIGNED(ed)) // 未对齐
        goto misalign;
    for (pgptr = bg; pgptr < ed; pgptr += PGSZ) {
        kfree (pgptr);
        // printk ("freeing pg %p\n", pgptr);
    }
    return 0;
    nopg:
    misalign:
    return -1;
}

int
kfree (void * pg) {
    sleep_lock (&freemem.lk);
    struct linkpgs * pgptr = (struct linkpgs *) pg;
    if (!PGALIGNED(pg)) goto misalign; // 未对齐
    pgptr->next = freemem.free;
    freemem.free = pgptr;
    sleep_unlock(&freemem.lk);
    return 0;
    misalign:
    sleep_unlock(&freemem.lk);
    return -1;
}

/* 分配失败返回 NULL, 分配时页面自动清零 */
void *
kalloc () {
    sleep_lock (&freemem.lk);
    struct linkpgs * allocpg;
    if (freemem.free == NULL)
        goto nomem;
    allocpg = freemem.free;
    freemem.free = allocpg->next;
    bzero (allocpg, PGSZ);
    sleep_unlock (&freemem.lk);
    return (void *) allocpg;
    nomem:
    sleep_unlock (&freemem.lk);
    return NULL;
}
